package com.yunkeji.config.init;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.yunkeji.common.constant.CacheConstants;
import com.yunkeji.common.msg.utils.BadWordDetectorUtils;
import com.yunkeji.common.utils.redis.RedisUtils;
import com.yunkeji.dao.domain.SysSensitiveWord;
import com.yunkeji.dao.mapper.SysSensitiveWordMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 内置缓存
 *
 * @author 老张
 */
@Configuration
@AllArgsConstructor
@Slf4j
public class CacheConfig {
    private final SysSensitiveWordMapper sysSensitiveWordMapper;

    @PostConstruct
    public void sensitiveWordInit() {
        List<SysSensitiveWord> sysSensitiveWords =
                sysSensitiveWordMapper.selectList(
                        Wrappers.lambdaQuery(SysSensitiveWord.class)
                                .select(SysSensitiveWord::getContent));
        if (CollectionUtil.isNotEmpty(sysSensitiveWords)) {
            Set<String> collect =
                    sysSensitiveWords.stream()
                            .map(SysSensitiveWord::getContent)
                            .collect(Collectors.toSet());
            RedisUtils.setCacheSet(CacheConstants.SENSITIVE_WORD, collect);
            log.info("初始化违禁词缓存,数量[{}]", collect.size());
        }
    }

    /**
     * 违禁词检测
     *
     * @author 老张
     */
    @Bean("sensitiveWordCheck")
    public LoadingCache<String, BadWordDetectorUtils> pushMessageInit() {
        LoadingCache<String, BadWordDetectorUtils> cache =
                CacheBuilder.newBuilder()
                        // 设置并发级别为8，并发级别是指可以同时写缓存的线程数
                        .concurrencyLevel(1)
                        // 设置缓存容器的初始容量为10
                        .initialCapacity(1)
                        // 设置缓存最大容量为100，超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                        .maximumSize(1)
                        // 是否需要统计缓存情况,该操作消耗一定的性能,生产环境应该去除
                        // .recordStats()
                        // 设置写缓存后n秒钟过期
                        // .expireAfterWrite(17, TimeUnit.SECONDS)
                        // 设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite
                        // .expireAfterAccess(1, TimeUnit.SECONDS)
                        // 只阻塞当前数据加载线程，其他线程返回旧值
                        // .refreshAfterWrite(13, TimeUnit.SECONDS)
                        // 设置缓存的移除通知
                        .removalListener(
                                notification -> {
                                    System.out.println(
                                            notification.getKey()
                                                    + " "
                                                    + notification.getValue()
                                                    + " 被移除,原因:"
                                                    + notification.getCause());
                                })
                        // build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
                        .build(
                                new CacheLoader<String, BadWordDetectorUtils>() {
                                    /** 缓存更新 */
                                    @Override
                                    public BadWordDetectorUtils load(String key) throws Exception {
                                        Set<String> cacheSet = RedisUtils.getCacheSet(key);
                                        log.info("刷新违禁词缓存,数量[{}]", cacheSet.size());
                                        // 创建新的违禁词检测机
                                        BadWordDetectorUtils badWordDetector =
                                                new BadWordDetectorUtils(cacheSet);
                                        return badWordDetector;
                                    }
                                });
        return cache;
    }
}
